package com.insigma.business.qrcode.common.util;

import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;


public class DateUtils extends org.apache.commons.lang3.time.DateUtils {

    private static final Logger LOGGER = LoggerFactory.getLogger(DateUtils.class);

    /**
     * 默认日期格式 //Timestamp format must be yyyy-mm-dd hh:mm:ss[.fffffffff]
     */
    private static final String DEFAULT_FORMAT = "yyyy-MM-dd HH:mm:ss";

    /**
     * 数据库中默认年月日格式
     */
    private static final String DEFAULT_FORMAT_DB = "yyyyMMdd";

    public static final String DEFAULT_FORMAT_YM = "yyyyMM";

    public static int getAgeByBirth(Date birthday) {
        Calendar cal = Calendar.getInstance();
        Calendar bir = Calendar.getInstance();
        bir.setTime(birthday);
        if (cal.before(bir)) {
            throw new IllegalArgumentException("The birthday is before Now,It's unbelievable");
        }
        int yearNow = cal.get(Calendar.YEAR);
        int monthNow = cal.get(Calendar.MONTH);
        int dayNow = cal.get(Calendar.DAY_OF_MONTH);
        int yearBirth = bir.get(Calendar.YEAR);
        int monthBirth = bir.get(Calendar.MONTH);
        int dayBirth = bir.get(Calendar.DAY_OF_MONTH);
        int age = yearNow - yearBirth;
        if (monthNow < monthBirth || (monthNow == monthBirth && dayNow < dayBirth)) {
            age--;
        }
        return age;
    }


    public static int getAgeByIdCardNo(String idNumber) {
        String dateStr;
        if (idNumber.length() == 15) {
            dateStr = "19" + idNumber.substring(6, 12);
        } else if (idNumber.length() == 18) {
            dateStr = idNumber.substring(6, 14);
        } else {
            return 0;
        }

        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd");
        try {
            Date birthday = simpleDateFormat.parse(dateStr);
            return getAgeByBirth(birthday);
        } catch (ParseException e) {
            return 0;
        }

    }


    public static Date getTimesmorning() {
        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.MILLISECOND, 0);
        return cal.getTime();
    }


    public static Date getYesterdaymorning() {
        Calendar cal = Calendar.getInstance();
        cal.setTimeInMillis(getTimesmorning().getTime() - 3600 * 24 * 1000);
        return cal.getTime();
    }


    public static Date getWeekFromNow() {
        Calendar cal = Calendar.getInstance();
        cal.setTimeInMillis(getTimesmorning().getTime() - 3600 * 24 * 1000 * 7);
        return cal.getTime();
    }


    public static Date getTimesnight() {
        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.HOUR_OF_DAY, 24);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.MILLISECOND, 0);
        return cal.getTime();
    }

    public static Date getTimesNight(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.set(Calendar.HOUR_OF_DAY, 24);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.MILLISECOND, 0);

        return cal.getTime();
    }


    public static Date getTimesWeekmorning() {
        Calendar cal = Calendar.getInstance();
        cal.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONDAY), cal.get(Calendar.DAY_OF_MONTH), 0, 0, 0);
        cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
        return cal.getTime();
    }


    public static Date getTimesWeeknight() {
        Calendar cal = Calendar.getInstance();
        cal.setTime(getTimesWeekmorning());
        cal.add(Calendar.DAY_OF_WEEK, 7);
        return cal.getTime();
    }


    public static Date getTimesMonthmorning() {
        Calendar cal = Calendar.getInstance();
        cal.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONDAY), cal.get(Calendar.DAY_OF_MONTH), 0, 0, 0);
        cal.set(Calendar.DAY_OF_MONTH, cal.getActualMinimum(Calendar.DAY_OF_MONTH));
        return cal.getTime();
    }


    public static Date getTimesNearMonthMorning(int num) {
        Calendar cal = Calendar.getInstance();
        cal.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONDAY) + num, cal.get(Calendar.DAY_OF_MONTH), 0, 0, 0);
        cal.set(Calendar.DAY_OF_MONTH, cal.getActualMinimum(Calendar.DAY_OF_MONTH));
        return cal.getTime();
    }


    public static Date getTimesMonthnight() {
        Calendar cal = Calendar.getInstance();
        cal.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONDAY), cal.get(Calendar.DAY_OF_MONTH), 0, 0, 0);
        cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
        cal.set(Calendar.HOUR_OF_DAY, 24);
        return cal.getTime();
    }

    public static Date getLastMonthStartMorning() {
        Calendar cal = Calendar.getInstance();
        cal.setTime(getTimesMonthmorning());
        cal.add(Calendar.MONTH, -1);
        return cal.getTime();
    }


    public static Date getCurrentQuarterStartTime() {
        Calendar c = Calendar.getInstance();
        int currentMonth = c.get(Calendar.MONTH) + 1;
        SimpleDateFormat longSdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        SimpleDateFormat shortSdf = new SimpleDateFormat("yyyy-MM-dd");
        Date now = null;
        try {
            if (currentMonth >= 1 && currentMonth <= 3)
                c.set(Calendar.MONTH, 0);
            else if (currentMonth >= 4 && currentMonth <= 6)
                c.set(Calendar.MONTH, 3);
            else if (currentMonth >= 7 && currentMonth <= 9)
                c.set(Calendar.MONTH, 6);
            else if (currentMonth >= 10 && currentMonth <= 12)
                c.set(Calendar.MONTH, 9);
            c.set(Calendar.DATE, 1);
            now = longSdf.parse(shortSdf.format(c.getTime()) + " 00:00:00");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return now;
    }


    public static Date getCurrentQuarterEndTime() {
        Calendar cal = Calendar.getInstance();
        cal.setTime(getCurrentQuarterStartTime());
        cal.add(Calendar.MONTH, 3);
        return cal.getTime();
    }

    private final static SimpleDateFormat shortSdf = new SimpleDateFormat("yyyy-MM-dd");

    public static Date getCurrentYearStartTime() {
        Date date = new Date();
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        Date dt = null;
        try {
            c.set(Calendar.MONTH, 0);
            c.set(Calendar.DATE, 1);
            dt = shortSdf.parse(shortSdf.format(c.getTime()));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return dt;
    }


    public static Date getCurrentYearEndTime() {
        Calendar cal = Calendar.getInstance();
        cal.setTime(getCurrentYearStartTime());
        cal.add(Calendar.YEAR, 1);
        return cal.getTime();
    }

    public static Date getLastYearStartTime() {
        Calendar cal = Calendar.getInstance();
        cal.setTime(getCurrentYearStartTime());
        cal.add(Calendar.YEAR, -1);
        return cal.getTime();
    }


    public static int daysBetween(Date smdate, Date bdate) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(smdate);
        long time1 = cal.getTimeInMillis();
        cal.setTime(bdate);
        long time2 = cal.getTimeInMillis();
        long betweenDays = (time2 - time1) / (1000 * 3600 * 24);
        return Integer.parseInt(String.valueOf(betweenDays));
    }

    public static int yearBetween(Date smdate, Date bdate) {
        try {
            Calendar cal = Calendar.getInstance();
            cal.setTime(smdate);
            long time1 = cal.getTimeInMillis();
            cal.setTime(bdate);
            long time2 = cal.getTimeInMillis();
            long betweenYears = (time2 - time1) / (1000 * 3600 * 24 * 365);
            return Integer.parseInt(String.valueOf(betweenYears));
        } catch (Exception e) {
            return 0;
        }

    }


    public static String format(Date date) {
        SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd", Locale.getDefault());
        return format.format(date);
    }

    public static String format(Date date, String format) {
        SimpleDateFormat sdf = new SimpleDateFormat(format, Locale.getDefault());
        return sdf.format(date);
    }

    public static int daysBetween(String smdate, String bdate) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Calendar cal = Calendar.getInstance();
        cal.setTime(sdf.parse(smdate));
        long time1 = cal.getTimeInMillis();
        cal.setTime(sdf.parse(bdate));
        long time2 = cal.getTimeInMillis();
        long betweenDays = (time2 - time1) / (1000 * 3600 * 24);
        return Integer.parseInt(String.valueOf(betweenDays));
    }


    public static int daysBetween(String smdate, Date bdate) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Calendar cal = Calendar.getInstance();
        cal.setTime(sdf.parse(smdate));
        long time1 = cal.getTimeInMillis();
        cal.setTime(bdate);
        long time2 = cal.getTimeInMillis();
        long betweenDays = (time2 - time1) / (1000 * 3600 * 24);
        return Integer.parseInt(String.valueOf(betweenDays));
    }


    public static int getWeekNum() {
        return getWeekNum(new Date());
    }

    public static int getWeekNum(Date date) {
        Calendar todayCal = Calendar.getInstance();
        todayCal.setTime(date);
        return todayCal.get(Calendar.WEEK_OF_YEAR);
    }

    public static String idCardNoToBirthday(String idCardNo) {
        if (StringUtils.isBlank(idCardNo) || idCardNo.length() < 15) {
            return "";
        }
        String y = idCardNo.substring(6, 10);
        String m = idCardNo.substring(10, 12);
        String d = idCardNo.substring(12, 14);
        return y + "-" + m + "-" + d;
    }


    public static List<Date> convertOperator(String operator) {
        if (Strings.isNullOrEmpty(operator)) {
            return null;
        }

        List<Date> result = Lists.newArrayList();
        if (operator.startsWith("M")) {
            int month = Integer.valueOf(operator.replace("M", ""));
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(new Date());
            calendar.set(Calendar.MONTH, month - 1);
            calendar.set(Calendar.DAY_OF_MONTH, 1);
            calendar.set(Calendar.HOUR_OF_DAY, 0);
            calendar.set(Calendar.MINUTE, 0);
            calendar.set(Calendar.SECOND, 0);
            result.add(calendar.getTime());
            calendar.add(Calendar.MONTH, 1);
            calendar.add(Calendar.MINUTE, -1);
            result.add(calendar.getTime());
            return result;
        }
        if (operator.startsWith("Q")) {
            int quarter = Integer.valueOf(operator.replace("Q", ""));
            Calendar calendar = Calendar.getInstance();
            calendar.set(Calendar.DAY_OF_MONTH, 1);
            calendar.set(Calendar.HOUR_OF_DAY, 0);
            calendar.set(Calendar.MINUTE, 0);
            calendar.set(Calendar.SECOND, 0);

            switch (quarter) {
                case 1:
                    calendar.set(Calendar.MONTH, 0);
                    result.add(calendar.getTime());
                    calendar.set(Calendar.SECOND, -1);
                    calendar.set(Calendar.MONTH, 3);
                    result.add(calendar.getTime());
                    break;
                case 2:
                    calendar.set(Calendar.SECOND, 1);
                    calendar.set(Calendar.MONTH, 3);
                    result.add(calendar.getTime());
                    calendar.set(Calendar.SECOND, -1);
                    calendar.set(Calendar.MONTH, 6);
                    result.add(calendar.getTime());
                    break;
                case 3:
                    calendar.set(Calendar.SECOND, 1);
                    calendar.set(Calendar.MONTH, 6);
                    result.add(calendar.getTime());
                    calendar.set(Calendar.SECOND, -1);
                    calendar.set(Calendar.MONTH, 9);
                    result.add(calendar.getTime());
                    break;
                case 4:
                    calendar.set(Calendar.SECOND, 1);
                    calendar.set(Calendar.MONTH, 9);
                    result.add(calendar.getTime());
                    calendar.set(Calendar.SECOND, -1);
                    calendar.set(Calendar.MONTH, 12);
                    result.add(calendar.getTime());
                    break;
                default:
                    break;
            }

            return result;
        }
        if (operator.startsWith("Y")) {
            int year = Integer.valueOf(operator.replace("Y", ""));
            Calendar calendar = Calendar.getInstance();
            calendar.set(Calendar.MONTH, 0);
            calendar.set(Calendar.DAY_OF_MONTH, 1);
            calendar.set(Calendar.HOUR_OF_DAY, 0);
            calendar.set(Calendar.MINUTE, 0);
            calendar.set(Calendar.SECOND, 0);
            calendar.set(Calendar.YEAR, year);
            result.add(calendar.getTime());

            calendar.add(Calendar.YEAR, 1);
            calendar.set(Calendar.SECOND, -1);
            result.add(calendar.getTime());
            return result;
        }
        return null;
    }

    public static List<Date> intersectionTime(String operator, Date startTime, Date endTime) {
        if (Strings.isNullOrEmpty(operator)) {
            return Lists.newArrayList(startTime, endTime);
        }

        if (startTime == null || endTime == null) {
            return convertOperator(operator);
        }

        List<Date> list = convertOperator(operator);
        Date stBefore = list.get(0);
        Date etBefore = list.get(1);
        return intersectionTime(stBefore, etBefore, startTime, endTime);
    }

    public static List<Date> intersectionTime(Date stBefore, Date etBefore, Date startTime, Date endTime) {
        if (stBefore.before(startTime) || stBefore.equals(startTime)) {
            if (etBefore.before(startTime) || etBefore.equals(startTime)) {
                return null;
            } else {
                if (etBefore.before(endTime) || etBefore.equals(endTime)) {
                    return Lists.newArrayList(startTime, etBefore);
                } else {
                    return Lists.newArrayList(startTime, endTime);
                }
            }
        } else {
            if (stBefore.before(endTime) || stBefore.equals(endTime)) {
                if (etBefore.before(endTime) || etBefore.equals(endTime)) {
                    return Lists.newArrayList(stBefore, etBefore);
                } else {
                    return Lists.newArrayList(stBefore, endTime);
                }
            } else {
                return null;
            }
        }
    }


    public static List<String> listNearDateStrs(Date base, int num, String format) {

        SimpleDateFormat formatBase = new SimpleDateFormat(format);
        List<String> result = new ArrayList<>();
        for (int i = 0; i < num; i++) {
            Date date = format.equals("yyyy") ? addYears(base, -i) : addMonths(base, -i);
            ;
            String item = formatBase.format(date);
            result.add(item);
        }
        return result;
    }


    public static List<String> listNearDatesOfDay(Date base, int num, String format) {
        SimpleDateFormat formatBase = new SimpleDateFormat(format);
        List<String> result = new ArrayList<>();
        for (int i = 0; i < num; i++) {
            Date date = addDays(base, -i);
            String item = formatBase.format(date);
            result.add(item);
        }
        return result;
    }

    public static List<String> listBetweenDays(Date startDate, Date endDate, String format) {
        if (endDate.compareTo(startDate) < 0) {
            return null;
        }
        SimpleDateFormat formatBase = new SimpleDateFormat(format);
        List<String> result = new ArrayList<>();

        String endTime = formatBase.format(endDate);
        int i = 0;
        while (true) {
            Date date = addDays(startDate, i++);
            String item = formatBase.format(date);
            if (endTime.compareTo(item) >= 0) {
                result.add(item);
            } else {
                break;
            }
        }
        return result;
    }

    public static List<Date> listNearDates(Date base, int num, String format) {
        SimpleDateFormat formatBase = new SimpleDateFormat(format);
        List<Date> result = new ArrayList<>();
        for (int i = 0; i < num; i++) {
            Date date = format.equals("yyyy") ? addYears(base, -i) : addMonths(base, -i);
            result.add(date);
        }
        return result;
    }

    public static List<String> listNearDateYear(int num) {
        Date date = DateUtils.addYears(DateUtils.getCurrentYearStartTime(), -1);
        List<String> strings = listNearDateStrs(date, num, "yyyy");
        return strings;
    }

    public static List<String> listNearDateMonthyyyyMM(int num) {
        Date date = DateUtils.addMonths(new Date(), -1);
        List<String> strings = listNearDateStrs(date, num, "yyyy-MM");
        return strings;
    }

    public static List<String> listNearDateMonthWithThisMonyhyyyyMM(int num) {
        Date date = new Date();
        List<String> strings = listNearDateStrs(date, num, "yyyy-MM");
        return strings;
    }

    public static List<String> listNearDateMonthMM(int num) {
        Date date = DateUtils.addMonths(new Date(), -1);
        List<String> strings = listNearDateStrs(date, num, "MM");
        return strings;
    }

    public static String convertDate(String dateStr, String oriFormat, String targetFormat) {
        try {
            SimpleDateFormat ori = new SimpleDateFormat(oriFormat);
            Date parse = ori.parse(dateStr);
            SimpleDateFormat tar = new SimpleDateFormat(targetFormat);
            return tar.format(parse);
        } catch (Exception e) {
            System.out.println(e);
        }
        return null;
    }


    public static Date getLastDayOfPreviousMonth() {
        Date currentDate = new Date();

        Calendar calendar = Calendar.getInstance();
        calendar.setTime(currentDate);

        calendar.add(Calendar.MONTH, -1);
        calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));

        Date lastDayOfPreviousMonth = calendar.getTime();

        return lastDayOfPreviousMonth;
    }

    /**
     * 字符串转换成日期 如果转换格式为空，则利用默认格式进行转换操作
     *
     * @param str    字符串
     * @param format 日期格式
     * @return 日期
     * @throws ParseException
     */
    public static Date str2Date(String str, String format) {
        if (null == str || "".equals(str)) {
            return null;
        }
        // 如果没有指定字符串转换的格式，则用默认格式进行转换
        if (null == format || "".equals(format)) {
            format = DEFAULT_FORMAT;
        }
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        Date date = null;
        try {
            date = sdf.parse(str);
            return date;
        } catch (ParseException e) {
            return null;
        }
    }

    /**
     * 日期转换为字符串
     *
     * @param date   日期
     * @param format 日期格式
     * @return 字符串
     */
    public static String date2Str(Date date, String format) {
        if (null == date) {
            return null;
        }
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        return sdf.format(date);
    }

    public static String date2Str(Date date) {
        if (null == date) {
            return null;
        }
        SimpleDateFormat sdf = new SimpleDateFormat(DEFAULT_FORMAT);
        return sdf.format(date);
    }

    public static void main(String[] args) throws ParseException {
        long b = 1000/356;
        System.out.println(b);
    }

}
